from Utilities import *

class Init:
	def __init__(self, conf, u = "", p = "", initDB=False):
		# Configuration Options
		self.dbroot = conf["dbroot"]
		self.delimiters = conf["delimiters"]
		self.validate = conf["validate-objects"]
		self.grammar = conf["grammar"]
		# User Information
		self.user = u
		self.passwd = p
		self.mod_sep = ","
		# User Levels
		self.READ = 0
		self.READ_WRITE = 1
		self.READ_WRITE_CREATE = 2
		self.READ_WRITE_ADMIN = 3
		# Sanity Check...
		if initDB == True:
			self.status = self.__initialize()
		else:
			self.status = ("null", "initDB bypassed.")
	
	def __initialize(self):
		if not checkDB(self.dbroot):
			if not createDB(self.dbroot, self.user, self.passwd):
				return generateError(28, "Could not create dbroot.", [ self.dbroot, self.user, self.passwd ])
		if not checkUserfile(self.dbroot):
			r = setUserfile(self.dbroot, { self.user : { "password" : Passwd(self.passwd), "level" : 3 }})
			if "error" in r:
				return generateError(32, "Could not create userfile for dbroot.", [ self.dbroot, self.user, self.passwd ])
		return generateStatus("Database Initialized", [ self.dbroot, self.user, self.passwd ])
		
	# GET #
	def Get(self, subject, obj):
		if not checkSubjectFormat(subject):
			return generateError(38, "Invalid Subject data format.", [ subject, obj ])
		if not checkObjectFormat(obj):
			return generateError(40, "Invalid Object data format.", [ subject, obj ])
		r = checkSubjectType(subject)
		if not r:
			return generateError(43, "Illegal subject name (reserved).", [ subject, obj ])
		elif r == "private":
			if not checkPermissions(self.Validate(getUserfile(self.dbroot, subject)), self.READ):
				return generateError(46, "Insufficient Permissions.", [ subject, obj ])
		elif r == "admin":
			return self.Admin("get", subject, obj)
		return loadObject(generateSubjectPath(self.dbroot, subject), generateObjectFilename(obj, self.delimiters))
	
	# SET #
	def Set(self, subject, obj, data):
		if not checkSubjectFormat(subject):
			return generateError(54, "Invalid Subject data format.", [ subject, obj, data ])
		if not checkObjectFormat(obj):
			return generateError(56, "Invalid Object data format.", [ subject, obj, data ])
		r = checkSubjectType(subject)
		if not r:
			return generateError(59, "Illegal Subject name (reserved).", [ subject, obj, data ])
		elif r == "private":
			if not checkSubjectExists(generateSubjectPath(self.dbroot, subject)):
				if not checkPermissions(self.Validate(getUserfile(self.dbroot)), self.READ_WRITE_CREATE):
					return generateError(63, "Insufficient Permissions to create Subject.", [ subject, obj, data ])
				if not createSubject(self.dbroot, subject):
					return generateError(65, "Unable to create Subject.", [ subject, obj, data ])
				else:
					user = { self.user : { "password" : Passwd(self.passwd), "level" : self.READ_WRITE_ADMIN }}
					if not setUserfile(self.dbroot, user, subject):
						return generateError(69, "Could not create Userfile for Subject '%s'." % subject["subject"], [ dbroot, user, subject ])
			else:
				if not checkPermissions(self.Validate(getUserfile(self.dbroot, subject)), self.READ_WRITE):
					return generateError(72, "Insufficient Permissions.", [ subject, obj, data ])
		elif r == "admin":
			return self.Admin("set", subject, obj, data)
		else:
			if not checkSubjectExists(generateSubjectPath(self.dbroot, subject)):
				if not checkPermissions(self.Validate(getUserfile(self.dbroot)), self.READ_WRITE_CREATE):
					return generateError(78, "Insufficient Permissions to create Subject.", [ subject, obj, data ])
				if not createSubject(self.dbroot, subject):
					return generateError(80, "Unable to create Subject.", [ subject, obj, data ])
		if self.validate:
			schema = getSchema(self.dbroot, subject, obj, self.delimiters)
			if not schema:
				schema = generateSchema(data)
				if "error" in schema:
					return schema
				else:
					r = saveObject(generateSubjectPath(self.dbroot, subject), generateObjectFilename(obj, self.delimiters), schema)
					if "error"  in r:
						return r
			else:
				if not validateObject(schema, data):
					return generateError(93, "Could not validate Data against Schema.", [ subject, obj, data, schema ])
		return saveObject(generateSubjectPath(self.dbroot, subject), generateObjectFilename(obj, self.delimiters), data)
		
	# LIST #
	def List(self, subject, obj):
		if not checkSubjectFormat(subject):
			return generateError(99, "Invalid Subject format", [ subject, obj ])
		if not checkObjectFormat(obj):
			return generateError(101, "Invalid Object format", [ subject, obj ])
		r = checkSubjectType(subject)
		if not r:
			return generateError(104, "Illegal Subject name (reserved).", [ subject, obj ])
		elif r == "private":
			if not checkPermissions(self.Validate(getUserfile(self.dbroot, subject)), self.READ):
				return generateError(107, "Insufficient Permissions.", [ subject, obj ])
		elif r == "admin":
			return self.Admin("list", subject, obj)
		r = getSubjectList(self.dbroot, subject)
		if not r:
			r = getObjectList(generateSubjectPath(self.dbroot, subject), obj, self.delimiters)
			if not r:
				return generateError(114, "Could not generate list.", [ subject, obj ])
		return { "list" : r, "data" : [ subject, obj ] }
		
	# REMOVE #
	def Remove(self, subject, obj):
		if not checkSubjectFormat(subject):
			return generateError(120, "Invalid Subject format.", [ subject, obj ])
		if not checkObjectFormat(obj):
			return generateError(122, "Invalid Object format", [ subject, obj ])
		r = checkSubjectType(subject)
		if not r:
			return generateError(125, "Illegal Subject name (reserved.)", [ subject, obj ])
		elif r == "private":
			if not checkPermissions(self.Validate(getUserfile(self.dbroot, subject)), self.READ_WRITE_CREATE):
				return generateError(128, "Insufficient Permissions to remove Objects.", [ subject, obj ])
		elif r == "admin":
			return self.Admin("remove", subject, obj)
		if deleteObject(generateSubjectPath(self.dbroot, subject), generateObjectFilename(obj, self.delimiters)):
			return generateStatus("Object Removed.", [ subject, obj ])
		else:
			return generateError(134, "Could not remove Object.", [ subject, obj ])
	
	# ADMIN #
	def Admin(self, verb, subject, obj, data=False):
		if checkAdminMode(subject) == "global":
			if not checkPermissions(self.Validate(getUserfile(self.dbroot)), self.READ_WRITE_ADMIN):
				return generateError(140, "User is not an Administrator.", [subject, obj, data ])
		else:
			if not checkPermissions(self.Validate(getUserfile(self.dbroot, subject)), self.READ_WRITE_ADMIN):
				return generateError(143, "User is not an administrator.", [ subject, obj, data ])
		
		if verb == "get":
			if checkAdminMode(subject) == "global":
				userfile = getUserfile(self.dbroot)
			else:
				userfile = getUserfile(self.dbroot, subject)
			if "error" in userfile:
				return userfile
			if not obj["object"] == "*":
				if obj["object"] in userfile:
					return { obj["object"] : userfile[obj["object"]] }
				else:
					return generateError(156, "User not found.", [ subject, obj ])
			else:
				return userfile
				
		elif verb == "set":
			if checkAdminMode(subject) == "global":
				userfile = getUserfile(self.dbroot)
			else:
				userfile = getUserfile(self.dbroot, subject)
			if "error" in userfile:
				return userfile
			if not obj["object"] in userfile:
				if not validateUserData(data):
					return generateError(169, "Invalid User data.", [ subject, obj, data ])
				data["password"] = Passwd(data["password"])
				userfile[obj["object"]] = data
			else:
				if not validateUserData(data):
					return generateError(173, "Invalid User data.", [ subject, obj, data ])
				data["password"] = Passwd(data["password"])
				userfile[obj["object"]] = data
			if checkAdminMode(subject) == "global":
				return setUserfile(self.dbroot, userfile)
			else:
				return setUserfile(self.dbroot, userfile, subject)
			
		elif verb == "remove":
			if obj["object"] == "User":
				# Remove User
				r = []
				if checkAdminMode(subject) == "global":
					userfile = getUserfile(self.dbroot)
				else:
					userfile = getUserfile(self.dbroot, subject)
				for u in obj["mods"]:
					if u in userfile:
						r.append(u)
						del userfile[obj["mods"][0]]
				return generateStatus("User(s) Removed.", r)
				
			if obj["object"] == "Subject":
				# Remove Subject
				if checkAdminMode(subject) == "global":
					# mods[0] = root dir
					if obj["mods"][0] == "*":
						# Remove all Subjects in Root...
						subjects = getSubjectList(self.dbroot, { "subject" : "*"})
						if not subjects:
							return generateError(203, "Could not get Subject List.", [ subject, obj ])
						for s in subjects:
							if not deleteSubject(AddSep(self.dbroot) + s):
								return generateError(206, "Could not remove Subjects.", [ subject, obj ])
						return generateStatus("Subjects removed.", [ subject, obj ])
					else:
						path = AddSep(self.dbroot) + self.delimiters[1].join(obj["mods"])
						if not deleteSubject(path):
							return generateError(211, "Could not remove Subject.", [ subject, obj ])
						return generateStatus("Subject removed.", [ subject, obj ])
				else:
					# if mods[0] = ** remove private dir, if * remove all dirs within private dir
					if obj["mods"][0] == "**":
						# subject["subject"] = subject["subject"][1:]
						if not deleteSubject(AddSep(self.dbroot) + subject["subject"]):
							return generateError(218, "Could not remove Private Subject.", [ subject, obj ])
						return generateStatus("Private Subject removed.", [ subject, obj ])
					elif obj["mods"][0] == "*":
						#subject["subject"] = subject["subject"][1:]
						subjects = getSubjectList(self.dbroot, subject, obj)
						if not subjects:
							return generateError(224, "Could not get Subject List.", [ subject, obj ])
						for s in subjects:
							if not deleteSubject(AddSep(self.dbroot) + s):
								return generateError(227, "Could not remove Subjects.", [ subject, obj ])
						return generateStatus("Subjects removed.", [ subject, obj ])
					else:
						if "*" in obj["mods"]:
							obj["mods"].remove("*")
							path = AddSep(self.dbroot) + AddSep(subject["subject"]) + "/".join(obj["mods"])
						else:
							path = AddSep(self.dbroot) + AddSep(subject["subject"]) + "/".join(obj["mods"])
						if not deleteSubject(path):
							return generateError(232, "Could not remove Subject.", [ subject, obj ])
						return generateStatus("Subject removed.", [ subject, obj ])
		else:
			return generateError(235, "Invalid Administrative command.", [ subject, obj, data, verb ])
	
	# VALIDATE #
	def Validate(self, userfile):
		if self.user in userfile:
			if Passwd(self.passwd) == userfile[self.user]["password"]:
				return userfile[self.user]["level"]
			else:
				return -1
		else:
			return -1
